// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

type testcase = (str, str, bool, []flag);

const testcases: [_]testcase = [
	// homegrown tests
	("a", "a", true, []),
	("b", "b", true, []),
	("ε", "ε", true, []),
	("\0", "\0", true, []),
	("abcde", "abcde", true, []),
	("aaa", "bbb", false, []),
	("わたし", "わたし", true, []),
	("わした", "わたし", false, []),
	("わaし", "わたし", false, []),

	("ab*cde", "abcde", true, []),
	("g*a", "gordana", true, []),
	("ab*cde*foo*bar", "abcdefooba", false, []),
	("*", "foo", true, []),
	("aa*", "aafoo", true, []),
	("bb*", "foo", false, []),
	("*cc", "foocc", true, []),
	("*dd", "foo", false, []),
	("ra**ra", "rarara", true, []),
	("x*yy*x", "xxyyyyyxxx", true, []),
	("*", "*", true, []),
	("*", "", true, []),
	("****", "a", true, []),
	("**a**", "a", true, []),
	("****", "", true, []),
	("*", "わたし", true, []),

	("?", "ε", true, []),
	("?", "\0", true, []),
	("?", "*", true, []),
	("?", "", false, []),
	("??", "a", false, []),
	("??", "abc", false, []),
	("?aa", "bbb", false, []),
	("わ?し", "わたし", true, []),
	("???", "わたし", true, []),

	("**?**", "", false, []),
	("*?*?*?*?", "abcd", true, []),
	("*?*?*?*?", "abc", false, []),

	("[b]", "b", true, []),
	("a[b]c", "abc", true, []),
	("a[b]c", "axc", false, []),
	("[a-c]", "b", true, []),
	("[a-z]", "a", true, []),
	("[c-a]", "b", false, []),
	("x[a-c]y", "xay", true, []),
	("x[a-c]y", "xby", true, []),
	("x[a-c]y", "xcy", true, []),
	("x[a-c]y", "xzy", false, []),
	("x[a-c]y", "xy", false, []),
	("[a-c]*[a-c]", "axxxb", true, []),
	("わ[た]し", "わたし", true, []),

	("[-]", "-", true, []),
	("[.]", ".", true, []),
	("[:ias]", ":", true, []),
	("[-]", "a", false, []),
	("[-ac]", "a", true, []),
	("[-ac]", "-", true, []),
	("[-ac]", "b", false, []),
	("[ac-]", "a", true, []),
	("[ac-]", "-", true, []),
	("[ac-]", "b", false, []),

	("[.a.]", "a", false, []),

	("[[:alnum:]]", "7", true, []),
	("[[:alpha:]]", "[", false, []),
	("[[:alpha:]]", "[[", false, []),
	("[[alpha:]]", "a]", true, []),
	("[[alpha:]]", ":]", true, []),
	("[[:alpha:]]", "a", true, []),
	("[[:blank:]]", " ", true, []),
	("[[:alnum:]]a", "a]a", false, []),
	("[[:alnum:][[:digit:]]", "a", true, []),

	("[!b]", "b", false, []),
	("a[!b]c", "abc", false, []),
	("a[!b]c", "axc", true, []),
	("[!a-c]", "b", false, []),
	("[!c-a]", "b", true, []),
	("x[!a-c]y", "xay", false, []),
	("x[!a-c]y", "xby", false, []),
	("x[!a-c]y", "xcy", false, []),
	("x[!a-c]y", "xzy", true, []),
	("x[!a-c]y", "xy", false, []),
	("[!a-c]*[!a-c]", "axxxb", false, []),
	("わ[!た]し", "わたし", false, []),

	("[!-]", "-", false, []),
	("[!-]", "a", true, []),
	("[!-ac]", "a", false, []),
	("[!-ac]", "-", false, []),
	("[!-ac]", "b", true, []),

	("[![:alnum:]]", "a", false, []),
	("[![:alpha:]]", "[", true, []),
	("[![:alnum:]]a", "a]a", false, []),
	("[![:alpha:]]a", "[a", true, []),
	("[![:alnum:][:digit:]]", "a", false, []),

	(".", ".", true, [flag::PERIOD]),
	("*", ".", false, [flag::PERIOD]),
	("?", ".", false, [flag::PERIOD]),
	("[.]", ".", false, [flag::PERIOD]),
	(".*", ".asdf", true, [flag::PERIOD]),
	(".*", "asdf", false, [flag::PERIOD]),

	("\\", "\\", true, [flag::NOESCAPE]),
	("\\*", "\\asdf", true, [flag::NOESCAPE]),

	// adapted from musl tests
	("*.c", "foo.c", true, []),
	("*.c", ".c", true, []),
	("*.a", "foo.c", false, []),
	("*.c", ".foo.c", true, []),
	("a\\*.c", "ax.c", false, []),
	("a[xy].c", "ax.c", true, []),
	("a[!y].c", "ax.c", true, []),
	("-O[01]", "-O1", true, []),
	("[[?*\\]", "\\", true, []),
	("[]?*\\]", "]", true, []),
	("[!]a-]", "b", true, []),
	("[]-_]", "^", true, []),
	("[!]-_]", "X", true, []),
	("??", "-", false, []),
	("[*]/b", "a/b", false, []),
	("[*]/b", "*/b", true, []),
	("[?]/b", "a/b", false, []),
	("[?]/b", "?/b", true, []),
	("[[a]/b", "a/b", true, []),
	("[[a]/b", "[/b", true, []),
	("\\*/b", "a/b", false, []),
	("\\*/b", "*/b", true, []),
	("\\?/b", "a/b", false, []),
	("\\?/b", "?/b", true, []),
	("[/b", "[/b", false, []),
	("\\[/b", "[/b", true, []),
	("??""/b", "aa/b", true, []),
	("???b", "aa/b", true, []),
	("a[/]b", "a/b", true, []),
	("*[/]b", "a", false, []),
	("[![:d-d]", "b", false, []),
	("[[:d-d]", "[", false, []),
	("[![:d-d]", "[", false, []),
	("[a-z]/[a-z]", "a/b", true, [flag::PATHNAME]),
	("a[/]b", "a/b", false, [flag::PATHNAME]),
	("*", "a/b", false, [flag::PATHNAME]),
	("*[/]b", "a/b", false, [flag::PATHNAME]),
	("*[b]", "a/b", false, [flag::PATHNAME]),
	("a[a/z]*.c", "a/x.c", false, [flag::PATHNAME]),
	("a/*.c", "a/x.c", true, [flag::PATHNAME]),
	("a*.c", "a/x.c", false, [flag::PATHNAME]),
	("*/foo", "/foo", true, [flag::PATHNAME]),
	("*.c", ".foo.c", false, [flag::PERIOD]),
	("*.c", "foo.c", true, [flag::PERIOD]),
	("a\\*.c", "a*.c", false, [flag::NOESCAPE]),
	("???b", "aa/b", false, [flag::PATHNAME]),
	("?a/b", ".a/b", false, [flag::PATHNAME, flag::PERIOD]),
	("a/?b", "a/.b", false, [flag::PATHNAME, flag::PERIOD]),
	("*a/b", ".a/b", false, [flag::PATHNAME, flag::PERIOD]),
	("a/*b", "a/.b", false, [flag::PATHNAME, flag::PERIOD]),
	("[.]a/b", ".a/b", false, [flag::PATHNAME, flag::PERIOD]),
	("a/[.]b", "a/.b", false, [flag::PATHNAME, flag::PERIOD]),
	("*/?", "a/b", true, [flag::PATHNAME, flag::PERIOD]),
	("?/*", "a/b", true, [flag::PATHNAME, flag::PERIOD]),
	(".*/?", ".a/b", true, [flag::PATHNAME, flag::PERIOD]),
	("*/.?", "a/.b", true, [flag::PATHNAME, flag::PERIOD]),
	("*/*", "a/.b", false, [flag::PATHNAME, flag::PERIOD]),
	("*?*/*", "a/.b", true, [flag::PERIOD]),
	("*[.]/b", "a./b", true, [flag::PATHNAME, flag::PERIOD]),
	("*[[:alpha:]]/*[[:alnum:]]", "a/b", true, [flag::PATHNAME]),
	("a?b", "a.b", true, [flag::PATHNAME, flag::PERIOD]),
	("a*b", "a.b", true, [flag::PATHNAME, flag::PERIOD]),
	("a[.]b", "a.b", true, [flag::PATHNAME, flag::PERIOD]),
];

@test fn fnmatch() void = {
	for (let tc .. testcases) {
		let flags = flag::NONE;
		for (let fl .. tc.3) {
			flags |= fl;
		};
		assert(fnmatch(tc.0, tc.1, flags) == tc.2);
	};

};
